import * as runtime from "./internal/runtime/mod";

// Describes the running Encore application.
export interface AppMeta {
  // The Encore application ID. If the application is not linked to the Encore platform this will be an empty string.
  // To link to the Encore platform run `encore app link` from your terminal in the root directory of the Encore app.
  appId: string;

  // The base URL which can be used to call the API of this running application.
  //
  // For local development it is "http://localhost:<port>", typically "http://localhost:4000".
  //
  // If a custom domain is used for this environment it is returned here, but note that
  // changes only take effect at the time of deployment while custom domains can be updated at any time.
  apiBaseUrl: string;

  // Information about the environment the app is running in.
  environment: EnvironmentMeta;

  // Information about the build.
  build: BuildMeta;

  // Information about the deployment.
  deploy: DeployMeta;
}

// Describes the environment the Encore application is running in.
export interface EnvironmentMeta {
  // The name of environment that this application.
  // For local development it is "local".
  name: string;

  // The type of environment is this application running in.
  // For local development it is "development".
  type: EnvironmentType;

  // The cloud this is running in.
  // For local development it is "local".
  cloud: CloudProvider;
}

// Describes what type of environment the application is running in.
export type EnvironmentType =
  // A production environment.
  | "production"
  // A long-lived cloud-hosted, non-production environment, such as test environments, or local development.
  | "development"
  // A short-lived cloud-hosted, non-production environments, such as preview environments
  | "ephemeral"
  // When running automated tests.
  | "test";

// Describes what cloud provider the application is running in.
export type CloudProvider =
  | "aws" // Amazon Web Services
  | "gcp" // Google Cloud Platform
  | "azure" // Microsoft Azure
  | "encore" // Encore Cloud.
  | "local"; // Local development

// Information about the build that formed the running application.
export interface BuildMeta {
  // The git commit that formed the base of this build.
  revision: string;

  // Whether there were uncommitted changes on top of the commit.
  uncommittedChanges: boolean;
}

// Information about the deployment of the running application.
export interface DeployMeta {
  // The unique id of the deployment. Generated by the Encore Platform.
  id: string;

  // The services hosted by this deployment, keyed by the service name. 
  hostedServices: Record<string, HostedService>;
}

export interface HostedService {
  // The name of the service
  name: string;
}

// Returns metadata about the running Encore application.
//
// The metadata is cached and is the same object each call,
// and therefore must not be modified by the caller.
export function appMeta(): AppMeta {
  // Compute the metadata on first use.
  if (cached === null) {
    let rt = runtime.RT.appMeta();
    cached = {
      appId: rt.appId,
      apiBaseUrl: rt.apiBaseUrl,
      environment: {
        name: rt.environment.name,
        type: envType(rt.environment.type),
        cloud: cloudProvider(rt.environment.cloud)
      },
      build: {
        revision: rt.build.revision,
        uncommittedChanges: rt.build.uncommittedChanges
      },
      deploy: {
        id: rt.deploy.id,
        hostedServices: rt.deploy.hostedServices
      }
    };
  }

  return cached;
}

function envType(rtType: runtime.EnvironmentType): EnvironmentType {
  switch (rtType) {
    case runtime.EnvironmentType.Production:
      return "production";
    case runtime.EnvironmentType.Development:
      return "development";
    case runtime.EnvironmentType.Ephemeral:
      return "ephemeral";
    case runtime.EnvironmentType.Test:
      return "test";
    default:
      return "development";
  }
}

function cloudProvider(rtType: runtime.CloudProvider): CloudProvider {
  switch (rtType) {
    case runtime.CloudProvider.AWS:
      return "aws";
    case runtime.CloudProvider.GCP:
      return "gcp";
    case runtime.CloudProvider.Azure:
      return "azure";
    case runtime.CloudProvider.Encore:
      return "encore";
    case runtime.CloudProvider.Local:
      return "local";
    default:
      return "local";
  }
}

// The cached app metadata. Set on first use.
let cached: AppMeta | null = null;
